<?php
/**
 * Image Processing Library (JImageLib)
 * 
 * 
 * @version     1.0
 * @package		JImageLib
 * @author 		Daniel Ghilea <danutz@gmail.com>
 * @copyright	Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
 * @license		GNU/GPL, see LICENSE.php
 * Joomla! is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 * See COPYRIGHT.php for copyright notices and details.
 */

jimport( 'joomla.html' );
jimport( 'joomla.factory' );
jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');

require_once('config.php');
//jimport( 'JImageLib.Config' );

class JImageLib extends JImageLibConfig{

	
	/*
	 * Image path
	 * 
	 * @var string 
	 */
	protected $path;
	
		
	/*
	 * Image width
	 * 
	 * @var int 
	 */
	protected $width = 0;
	
	
	/*
	 * Image height
	 * 
	 * @var int 
	 */
	protected $height = 0;
	
	
	/*
	 * Properties of the loaded image
	 * 
	 * @var array 
	 */
	protected $img = array();
	
	
	/*
	 * Reference to the temporary image (for GD) or filename (for IM and GM)
	 * 
	 * @var object/string
	 */
	protected $temp;
	
	
		
	/*
	 * Filename escaped to be used as a shell argument (for IM and GM)
	 * 
	 * @var string 
	 */
	protected $temp_esc = '';
	
	
	
	/*
	 * IM and GM directory
	 * 
	 * @var string 
	 */
	protected $dir = '';
	
	
	/*
	 * IM and GM extension ( '.exe' for Windows and '' for Unix)
	 * 
	 * @var string 
	 */
	protected $ext = '';
	
	
	

	
	/*
	 * Image library that is going to be used for processing
	 * 
	 * Options available: 
	 * "gd", "im", "gm"
	 * 
	 * @var string 
	 */
	protected $imageLib;
	
	
	
	/*
	 * Alt text
	 * 
	 * @var string
	 */
	protected $alt = "";
	
	/*
	 * Image title
	 * 
	 * @var string
	 */
	protected $title = "";

	/*
	 * <img> css class attribute
	 * 
	 * @var string
	 */
	protected $class = "";
	
	/*
	 * <img> id attribute
	 * 
	 * @var string
	 */
	protected $id = "";
	
	/*
	 * Pop-up type used when generating a tag. 
	 * 
	 * Options available: 
	 * "none", "lightbox", "greybox"
	 * 
	 * @var string
	 */
	protected $popUp = JImageLib::DEFAULT_POPUP_TYPE;

	/*
	 * <img> other attributes
	 * 
	 * @var string
	 */
	protected $attributes = "";
		
	
	/*
	 * Directory where the generated images will be saved
	 * 
	 * @var string
	 */
	protected $directory = JImageLib::DEFAULT_DIRECTORY;
	
	
	/*
	 * Prefix for the generated images
	 * 
	 * @var string
	 */
	protected $prefix = JImageLib::DEFAULT_PREFIX;
	
	/*
	 * How is included the new image size into the name of generated images
	 * 
	 * @var string
	 */
	protected $useImgSize = JImageLib::DEFAULT_USE_IMG_SIZE;
	
	/*
	 * Custom name for the next generated image
	 * 
	 * @var string
	 */
	protected $customName;
	
	/*
	 * Cache expiration time
	 * 
	 * @var int
	 */
	protected $cache = JImageLib::DEFAULT_CACHE;
	
	/*
	 * Error messages
	 * 
	 * @var array 
	 */
	protected $errors = array();
	
	
	/*
	 * Actions that will be done to the image
	 * 
	 * @var array 
	 */
	protected $actions = array();
	
	
	/*
	 * Library language array
	 * 
	 * @var array
	 */
	protected $language = array();
	

	/*
	 * Img types supported
	 * 
	 * @var	array
	 */

	protected $supportedTypes = array(IMAGETYPE_GIF => "gif", IMAGETYPE_JPEG =>"jpg",IMAGETYPE_PNG => "png");



	/*
	 * Img processors
	 * 
	 * @var	array
	 */

	protected $imgProcessors = array("gd", "im", "gm");


	/*
	 * Img naming options
	 * 
	 * @var	array
	 */

	protected $imgSizeMode = array("both", "dir", "file", "none");



	/*
	 * Pop-up types
	 * 
	 * @var	array
	 */

	protected $popups = array( "none", "slimbox", "greybox");




	/*
	 * Filter types
	 * 
	 * @var	array
	 */

	protected $filters = array("dropshadow", "grayscale", "sepia", "negative", "blur", "invert",
							"edgedetect", "meanremoval", "emboss", "brightness", "contrast", "smoothness", "colorize");

	/*
	 * Filters that need parameters
	 * 
	 * @var	array
	 */
	protected $filtersWithParams = array("brightness", "contrast", "smoothness", "colorize");



	/*
	 * Flip directions
	 * 
	 * @var	array
	 */

	protected $flip = array("h", "v");



	/*
	 * Resizing options
	 * 
	 * @var	array
	 */

	protected $resizeOptions = array( "bestfit", "crop", "fill", "stretch");




	/*
	 * Watermark positions
	 * 
	 * @var	array
	 */

	protected $watermarkPositions = array("center", "top", "topright", "topleft",	"bottom", "bottomright", "bottomleft", "right", "left", "random");

	

	/*
	 * RegEx for processing scripting language tags
	 * 
	 * @var	array
	 */

	protected $RegEx;
	

	
	/*
	 * Constructor
	 * 
	 * Sets the default directory by calling the related method and RegEx constants
	 * 
	 */
	
	
	
	function __construct()
	{
		
		$this->setDirectory(JImageLib::DEFAULT_DIRECTORY);

		$this->RegEx['src'] = '/((src\s*=\s*)?(["\'])?)((.*?)\.(jpg|jpeg|png|gif))(["\'])?\s/i';
		$this->RegEx['width'] = '/width\s*(=\s*)?(["\'])?([1-9][0-9]*?)(["\'])?\s/i';
		$this->RegEx['height'] = '/height\s*(=\s*)?(["\'])?([1-9][0-9]*?)(["\'])?\s/i';
		$this->RegEx['imagelib'] = '/imageLib\s*(=\s*)?(["\'])?(im|gd|gm)(["\'])?\s/i';
		$this->RegEx['alt'] = '/alt\s*(=\s*)?("[^"]*"|\'[^\']*\')\s/i';
		$this->RegEx['title'] = '/title\s*(=\s*)?("[^"]*"|\'[^\']*\')\s/i';
		$this->RegEx['class'] = '/class\s*(=\s*)?("[^"]*"|\'[^\']*\')\s/i';
		$this->RegEx['id'] = '/id\s*(=\s*)?("[^"]*"|\'[^\']*\')\s/i';
		$this->RegEx['brightness'] = '/brightness\s*(=\s*)?(["\'])?(\+|-)?([1-9][0-9]?[0-9]?)(["\'])?\s/i';
		$this->RegEx['contrast'] = '/contrast\s*(=\s*)?(["\'])?(\+|-)?([1-9][0-9]?[0-9]?)(["\'])?\s/i';
		$this->RegEx['smoothness'] = '/smoothness\s*(=\s*)?(["\'])?(\+|-)?([1-9][0-9]?[0-9]?)(["\'])?\s/i';
		$this->RegEx['colorize'] = '/colorize\s*(=\s*)?(["\'])?\#?([0-9a-f]{1,2}){3}(["\'])?\s/i';
		$this->RegEx['flip'] = '/flip\s*(=\s*)?(["\'])?(h|v)(["\'])?\s/i';
		$this->RegEx['rotate'] = '/rotate\s*(=\s*)?(["\'])?(\+|-)?([1-9]([0-9]*)?)(["\'])?\s/i';
		$this->RegEx['top'] = '/top\s*(=\s*)?(["\'])?(\+|-)?([1-9]([0-9]*)?)(["\'])?\s/i';
		$this->RegEx['left'] = '/left\s*(=\s*)?(["\'])?(\+|-)?([1-9]([0-9]*)?)(["\'])?\s/i';
		$this->RegEx['resize'] = '/resize\s*(=\s*)?(["\'])?(bestfit|crop|fill|stretch)(["\'])?\s/i';
		$this->RegEx['fill-color'] = '/fill-color\s*(=\s*)?(["\'])?\#?([0-9a-f]{1,2}){3}(["\'])?\s/i';
		
		$this->RegEx['wm-file'] = '/wm-file\s*(=\s*)?(["\'])?((.*?)\.png)(["\'])?\s/i';
		$this->RegEx['wm-position'] = '/wm-position\s*(=\s*)?(["\'])?(center|top|topright|topleft|bottom|bottomright|bottomleft|right|left|random)(["\'])?\s/i';
		$this->RegEx['wm-top-margin'] = '/wm-top-margin\s*(=\s*)?(["\'])?(\+|-)?([1-9]([0-9]*)?)(["\'])?\s/i';
		$this->RegEx['wm-left-margin'] = '/wm-left-margin\s*(=\s*)?(["\'])?(\+|-)?([1-9]([0-9]*)?)(["\'])?\s/i';
		$this->RegEx['wm-transparency'] = '/wm-transparency\s*(=\s*)?(["\'])?([1-9][0-9]?[0-9]?)(["\'])?\s/i';
		
		$this->RegEx['wm-text'] = '/wm-text\s*(=\s*)?("[^"]*"|\'[^\']*\')\s/i';
		$this->RegEx['wm-font-family'] = '/wm-font-family\s*(=\s*)?("[^"]*"|\'[^\']*\')\s/i';
		$this->RegEx['wm-font-size'] = '/wm-font-size\s*(=\s*)?(["\'])?([1-9][0-9]?)(["\'])?\s/i';
		$this->RegEx['wm-font-color'] = '/wm-font-color\s*(=\s*)?(["\'])?\#?([0-9a-f]{1,2}){3}(["\'])?\s/i';
		
		
		$this->RegEx['popup'] = '/popup\s*(=\s*)?(["\'])?(slimbox|greybox|none)(["\'])?\s/i';
		$this->RegEx['pop-up'] = '/pop-up\s*(=\s*)?(["\'])?(slimbox|greybox|none)(["\'])?\s/i';
		$this->RegEx['quality'] = '/quality\s*(=\s*)?(["\'])?(\+|-)?([1-9]([0-9]*)?)(["\'])?\s/i';
		
				
	}
	
	
	
	
	/*
	 * Overridden get method to get image properties
	 * 
	 * @access	private
	 * @param	string	$property	The name of the property to get
	 * @param	mixed  	$default	The default value
	 * @return	mixed				The value of the property
	 * 
	 */
	
	private function get($property, $default = null)
	{
		if (isset($this->$property)){
			return $this->$property;
		}
		return $default;
	}
	
	
	
	/*
	 * Overridden set method to set image properties
	 * 
	 * @access	private
	 * @param	string	$property	The name of the property to set
	 * @param	mixed  	$value		The  value for the property
	 * @return	boolean				True on success
	 * 
	 */
	
	private function set($property, $value = null)
	{
		if ($this->$property = $value){
			return true;
		}
		else return false;
	}
	
	

	/*
	 * Gets the image path
	 * 
	 * @return  string		The path to the image
	 * 
	 */
	
	function getPath()
	{
		return $this->get('path');
	}

	
	/*
	 * Sets the image path
	 * 
	 * @param  string	$path		The path to the image to load
	 * 
	 */
	
	function setPath($path)
	{
		$path = JPATH_SITE . DS . $path;
		if (!JFile::exists($path)) {
			$this->setError($this->__("ERROR_FILE_NOT_FOUND"));
			return false;
		}
		
		$img_info = getimagesize($path);
		if ((!is_array($img_info)) OR (count($img_info) < 3)){
			$this->setError($this-> __("ERROR_INVALID_FILE"));
			return false;
		}
		
		if(! isset($this->supportedTypes[$img_info[2]]) ){
			$this->setError($this-> __("ERROR_INVALID_TYPE"));
			return false;
		}
		
		$this->img['path'] = str_replace('\\', '/', realpath($path));
		$this->img['width'] = $img_info[0];
		$this->img['height'] = $img_info[1];
		$this->img['ext'] = $this->supportedTypes[$img_info[2]];
		$this->img['mime'] = $img_info['mime'];
		
		$site_path = str_replace('\\', '/', realpath(JPATH_SITE)) . '/';
		$path = str_replace($site_path, '', $path);
		 
		return $this->set('path', $path);
	}
	
	
	
	/*
	 * Loads the image from the specified image path
	 * 
	 * @param  string	$path		The path to the image to load
	 * 
	 */
	
	function load($path)
	{
		return $this->setPath($path);
	}
	
	
	
	/*
	 * Gets image width
	 * 
	 * @return  int		The width of the image
	 * 
	 */
	
	function getWidth()
	{
		return $this->get('width', 0);
	}

	
	
	/*
	 * Sets new image width
	 * 
	 * @param  int	$width		The new width for the image
	 * 
	 */
	
	function setWidth($width)
	{
		if (!is_int($width) || $width < 0){
			$this->setError($this->__("ERROR_INVALID_WIDTH"));
			return false;
		}
		return $this->set('width', $width);
	}
	
	
	
	/*
	 * Gets image height
	 * 
	 * @return  int		The height of the image
	 * 
	 */
	
	function getHeight()
	{
		return $this->get('height', 0);
	}
	
	
	
	/*
	 * Sets new image height
	 * 
	 * @param  int	$height		The new height for the image
	 * 
	 */
	
	function setHeight($height)
	{
		if (!is_int($height) || $height < 0){
			$this->setError($this->__("ERROR_INVALID_HEIGHT"));
			return false;
		}
		return $this->set('height', $height);
	}
	
	
	
	/*
	 * Gets image processing system
	 * 
	 * @return  string		The image 3rd party library used for image processing
	 * 
	 */
	
	function getImageLib()
	{
		return $this->get('imageLib', JImageLib::DEFAULT_IMG_PROCESSOR);
	}
	
	
	
	/*
	 * Sets image processing system
	 * 
	 * Options available: 
	 * "gd", "im", "gm"
	 * 
	 * @param  string	$imageLib		The new image 3rd party library used for image processing
	 * 
	 */
	
	function setImageLib($imageLib = JImageLib::DEFAULT_IMG_PROCESSOR)
	{
		if (! in_array(strtolower($imageLib), $this->imgProcessors)){
			$this->setError($this-> __("ERROR_INVALID_IMG_LIB"));
			return false;
		}
		
				
		if (! $this->loadImageLib(strtolower($imageLib))){
			return false;
		}

		return $this->set('imageLib', strtolower($imageLib));
	}
	
	
	
	
	/*
	 * Loads the image processing system
	 * 
	 * 
	 * @param  string	$imageLib		The image 3rd party library used for image processing
	 * 
	 */
	
	private function loadImageLib($imageLib)
	{
		switch ($imageLib){
			
			case $this->imgProcessors[0]:
				/*
				 * Un-comment the following line to increase the memory limit 
				 * (used for GD processing)
				 * 
				 */
				// ini_set('memory_limit', '64M');
				
				
				if (! function_exists('gd_info')){
					$this->setError($this->__("ERROR_CANNOT_LOAD_GD"));
					return false;
				}
				$gd_info = gd_info();
				$version = $gd_info['GD Version'];
			
				if (strpos($version, '2.') === false){
					$this->setError($this->__("ERROR_CANNOT_LOAD_GD"));		
					return false;
				}
			break;

			case $this->imgProcessors[1]: 
				if (PHP_SHLIB_SUFFIX == 'dll') $this->ext = '.exe';

				if (JImageLib::DEFAULT_IMAGE_MAGICK_DIRECTORY == ''  || ! is_file(realpath(JImageLib::DEFAULT_IMAGE_MAGICK_DIRECTORY) .'/'. 'convert' . $this->ext ) ){
					$this->setError($this->__("ERROR_CANNOT_LOAD_IM"));		
					return false;
				}
				$this->dir = str_replace('\\', '/', realpath(JImageLib::DEFAULT_IMAGE_MAGICK_DIRECTORY)) . '/';
			break;
			
			case $this->imgProcessors[2]: 
				if (PHP_SHLIB_SUFFIX == 'dll') $this->ext = '.exe';
				
				if (JImageLib::DEFAULT_GRAPHICS_MAGICK_DIRECTORY == ''  || ! is_file(realpath(JImageLib::DEFAULT_GRAPHICS_MAGICK_DIRECTORY) .'/'. 'gm' . $this->ext ) ){
					$this->setError($this->__("ERROR_CANNOT_LOAD_IM"));		
					return false;
				}
				$this->dir = str_replace('\\', '/', realpath(JImageLib::DEFAULT_GRAPHICS_MAGICK_DIRECTORY)) . '/';
			break;
		}

		return true;
	}
	
	
	/*
	 * Gets alt text
	 * 
	 * @return  string		The alt text of the image
	 * 
	 */
	
	function getAlt()
	{
		return $this->get('alt');
	}
	

	
	/*
	 * Sets the alt text
	 * 
	 * @param  string	$alt	The new alt text for the image
	 * 
	 */
	
	function setAlt($alt)
	{
		return $this->set('alt', htmlspecialchars(strip_tags($alt)) );
	}
	
	
	
	/*
	 * Gets the image title
	 * 
	 * @return  string		The title of the image
	 * 
	 */
	
	function getTitle()
	{
		return $this->get('title');
	}
	

	
	/*
	 * Sets the image title
	 * 
	 * @param  string	$title		The new title for the image
	 * 
	 */
	
	function setTitle($title)
	{
		return $this->set('title', htmlspecialchars(strip_tags($title)) );
	}
	
	
	
	/*
	 * Gets the css class
	 * 
	 * @return  string		The css class of the image
	 * 
	 */
	
	function getClass()
	{
		return $this->get('class');
	}
	
	
	
	/*
	 * Sets the css class
	 * 
	 * @param  string	$class		The new css class for the image
	 * 
	 */
	
	function setClass($class)
	{
		return $this->set('class', htmlspecialchars(strip_tags($class)) );
	}
	
	
	
	/*
	 * Gets the <img> id attribute
	 * 
	 * @return  string		The id attribute of the image
	 * 
	 */
	
	function getId()
	{
		return $this->get('id');
	}
	
	
	
	/*
	 * Sets the <img> id attribute
	 * 
	 * @param  string	$id		The new id attribute for the image
	 * 
	 */
	
	function setId($id)
	{
		return $this->set('id', htmlspecialchars(strip_tags($id)) );
	}
	

	
	/*
	 * Gets the pop-up type
	 * 
	 * @return  string		The pop-up type used when generating a tag.
	 * 
	 */
	
	function getPopUp()
	{
		return $this->get('popUp', JImageLib::DEFAULT_POPUP_TYPE);
	}
	

	
	/*
	 * Sets the pop-up type
	 * 
	 * Options available: 
	 * "none", "lightbox", "greybox"
	 * 
	 * @param  string	$popUp		The pop-up type used when generating a tag.
	 * 
	 */
	
	function setPopUp($popUp)
	{
		if (! in_array(strtolower($popUp), $this->popups)){
			$this->setError($this-> __("ERROR_INVALID_POPUP"));
			return false;
		}
		return $this->set('popUp', $popUp);
	}
	
	
	
	/*
	 * Gets other attributes string
	 * 
	 * @return  string		The other attributes used when generating a tag.
	 * 
	 */
	
	function getAttributes()
	{
		return $this->get('attributes');
	}
	
	
	
	/*
	 * Sets other attributes string
	 * 
	 * @param  string	$att		The other attributes used when generating a tag.
	 * 
	 */
	
	function setAttributes($att)
	{
		return $this->set('attributes', htmlspecialchars(strip_tags($att)) );
	}


		
	/*
	 * Gets the directory where the generated images will be saved
	 * 
	 * @return  string		Directory
	 * 
	 */
	
	function getDirectory()
	{
		return $this->get('directory', JImageLib::DEFAULT_DIRECTORY);
	}
	
	
	/*
	 * Sets the new directory for saving the generated images
	 * 
	 * @param  string	$newDirectory		The directory in which images will be saved
	 * 
	 */
	
	function setDirectory($newDirectory)
	{
		if ($newDirectory == ''){
			$this->directory = '';
			return true;
		}
		
		$newDirectory = JPATH_SITE . DS . $newDirectory;
		$tmp = str_replace('\\', '/', $newDirectory);
		
		if (! file_exists($tmp)){
			if (!mkdir($tmp)){
				$this->setError($this-> __("ERROR_INVALID_DIRECTORY"));
				return false;
			}
		}
		
		$tmp = str_replace('\\', '/', realpath($newDirectory));
		if (! is_writable($tmp)){
			$this->setError($this-> __("ERROR_INVALID_DIRECTORY"));
			return false;
		}
		return $this->set('directory', $newDirectory);
	}
	
	
	
	/*
	 * Gets the prefix for the generated images
	 * 
	 * @return  string		Prefix for naming generated images
	 * 
	 */
	
	function getPrefix()
	{
		return $this->get('prefix', JImageLib::DEFAULT_PREFIX);
	}
	

	/*
	 * Sets the new prefix for the generated images
	 * 
	 * @param  string	$newPrefix		The prefix for generated images
	 * 
	 */
	
	function setPrefix($newPrefix)
	{
		return $this->set('prefix', $newPrefix );
	}
	
	
	
	/*
	 * Gets how including the new image size into the name is handled
	 * 
	 * @return  string		Handling mode
	 * 
	 */
	
	function getUseImageSize()
	{
		return $this->get('useImgSize', JImageLib::DEFAULT_USE_IMG_SIZE);
	}
	
	
	
	
	/*
	 * Sets how to include the new image size into the name or containing directory
	 * 
	 * @param  string	$mode		The handling mode
	 * 
	 */
	
	function setUseImageSize($mode)
	{
		if (! in_array(strtolower($mode), $this->imgSizeMode)){
			$this->setError($this-> __("ERROR_INVALID_IMG_SIZE_MODE"));
			return false;
		}
		
		return $this->set('useImgSize', strtolower($mode));
	}
	
	
	
	
	/*
	 * Gets custom name for the next generated image
	 * 
	 * @return  string		The custom name for the next generated image
	 * 
	 */
	
	function getName()
	{
		return $this->get('customName');
	}
	
	
	/*
	 * Sets new custom name for each generated image
	 * 
	 * @param  string	$customName		New custom name
	 * 
	 */
	
	function setName($customName)
	{
		if ($customName == ''){
			$this->customName = '';
			return true;
		}
		return $this->set('customName', JPATH_SITE . DS . $customName );
	}
	
	
	/*
	 * Gets cache expiration time
	 * 
	 * @return  int		Cache expiration time
	 * 
	 */
	
	function getCacheTime()
	{
		return $this->get('cache');
	}
	
	
	/*
	 * Sets cache expiration time. If it is set to 0, then caching is disabled
	 * 
	 * @param  int	$time		Cache expiration time
	 * 
	 */
	
	function setCacheTime($time = 0)
	{
		return $this->set('cache', $time );
	}
	

		
	/*
	 * Sets the filter type
	 * 
	 * Options available: 
	 *  grayscale, sepia, negative, blur, invert, edgeDetect, meanRemoval, emboss, dropShadow 
	 *
	 * Options requiring parameter :
	 *  brightness, contrast, smoothness, colorize
	 * 
	 * @param  string	$filterType		Type of the filter that will be applied
	 * @param  int		$value			Value for the filters that require parameter
	 *									For colorize, it represents the hex
	 *									code of the color
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	function setFilter($filterType, $value = null )
	{
		if (! in_array(strtolower($filterType), $this->filters)){
			$this->setError($this-> __("ERROR_INVALID_FILTER"));
			return false;
		}
		
		if (in_array(strtolower($filterType), $this->filtersWithParams)){
			if ($value == null) {
				$this->setError($this-> __("ERROR_NO_FILTER_PARAM"));
				return false;
			}
			if ((!is_int($value) || $value < -100 || $value > 100 ) && (strtolower($filterType) != "colorize")){
				$this->setError($this-> __("ERROR_INVALID_FILTER_PARAM"));
				return false;
			}	
				
			if (strtolower($filterType) == 'colorize'){
				if ( ! list($r, $g, $b) = $this->getColor($value)){
					$this->setError($this-> __("ERROR_INVALID_COLOR"));
					return false;			
				}
				$this->actions[strtolower($filterType)] = array('r' => $r, 'g' => $g, 'b' => $b);
			}
			else $this->actions[strtolower($filterType)] = $value;
		}
		else $this->actions[strtolower($filterType)] = true;
		return true;
	}
	
	
	
	/*
	 * Sets the option to flip an image along the horizontal or vertical axis
	 * 
	 * Options available:
	 * 'H' or 'V'  
	 *   
	 * @param  string	$direction		The direction for flipping
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	function setFlipping($direction)
	{
		if (! in_array(strtolower($direction), $this->flip)){
			$this->setError($this-> __("ERROR_INVALID_FLIP"));
			return false;
		}
		
		$this->actions['flip'] = strtolower($direction);
		return true;
	}
	
	
	
	
	/*
	 * Sets the angle for rotating the image.
	 * 
	 * The angle should be positive value for a clockwise rotation and negative value for a counter-clockwise rotation
	 * 
	 * 
	 * @param  string	$angle		Angle degrees for the rotation
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	function setRotation($angle)
	{

		if (!is_int($angle)){
				$this->setError($this-> __("ERROR_INVALID_ROTATION_ANGLE"));
				return false;
		}	
		
		if ($angle > 180){
			while ($angle > 180) $angle -= 360;
		}
		if ($angle < -180){
			while ($angle < -180) $angle += 360;
		}
		
		
		$this->actions['rotate'] = $angle;
		return true;
	}
	

	
	/*
	 * Sets the options for cropping image to the specified dimensions
	 * 
	 * 
	 * @param  int	$top		Top margin for cropping
	 * @param  int	$left		Left margin for cropping
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	function setCropping($top = JImageLib::DEFAULT_TOP_CROP, $left = JImageLib::DEFAULT_LEFT_CROP)
	{

		if (!is_int($top)){
				$this->setError($this-> __("ERROR_INVALID_CROP_TOP"));
				return false;
		}	
		if (!is_int($left)){
				$this->setError($this-> __("ERROR_INVALID_CROP_LEFT"));
				return false;
		}	

		$width = $this->getWidth();
		$height = $this->getHeight();
		
		if ($width == 0 || $height == 0){
			$this->setError($this-> __("ERROR_INVALID_CROP_SIZE"));
			return false;
		}
		
		$this->actions['crop'] = array('width' => $width, 'height'=> $height, 'top' => $top, 'left' => $left );
		return true;
	}
	

	
	
	/*
	 * Sets options for resizing an image to the new dimensions
	 * 
	 * 
	 * @param  string	$option		How to handle aspect ratio
	 * @param  string	$color		Code of the color used to fill the background, if option is fill
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	function setResizing($option = JImageLib::DEFAULT_RESIZE_OPTION, $color = JImageLib::DEFAULT_RESIZE_COLOR)
	{
		if (! in_array(strtolower($option), $this->resizeOptions)){
			$this->setError($this-> __("ERROR_INVALID_RESIZE_OPTION"));
			return false;
		}

		if (! $this->getColor($color)){
			$this->setError($this-> __("ERROR_INVALID_COLOR"));
			return false;			
		}

		$width = $this->getWidth();
		$height = $this->getHeight();
		
		if ($width == 0 && $height == 0){
			$this->setError($this-> __("ERROR_INVALID_SIZE"));
			return false;
		}
		
		if (($width == 0 || $height == 0) && (strtolower($option) == "crop" || strtolower($option) == "fill") ){
			$this->setError($this-> __("ERROR_INVALID_CROP_SIZE"));
			return false;
		}
		
		$this->actions['resize'] = array('width' => $width, 'height'=> $height, 'option' => strtolower($option), 'color' => $color );
		return true;
	}
	

	
	
	/*
	 * Returns the last generated error message
	 * 
	 * @return  string		Error message
	 * 
	 */
	
	function getError()
	{
		if (sizeof($this->errors) < 1) return false;
		return $this->errors[sizeof($this->errors) - 1];
	}
	
	
	
	
	/*
	 * Adds another error message.
	 *   
	 * @param  string	$error		The error message
	 * 
	 */
	
	function setError($error)
	{
		return $this->errors[] = $error;
	}
	
	
	
	
	/*
	 * Converts a hex color code into RGB values
	 *   
	 * @param  string	$code		The color code
	 * 
	 * @return	array				Array with RGB values
	 */
	
	function getColor($code)
	{
		if ($code[0] == '#') $code = substr($code, 1);
		if (strlen($code) != 6 && strlen($code) != 3) return false;
		else if (strlen($code) == 3){
			$r = hexdec($code[0].$code[0]);
			$g = hexdec($code[1].$code[1]);
			$b = hexdec($code[2].$code[2]);
		}
		else if (strlen($code) == 6){
			$r = hexdec($code[0].$code[1]);
			$g = hexdec($code[2].$code[3]);
			$b = hexdec($code[4].$code[5]);
		}
		
		return array($r, $g, $b);
	}
	
	
	
	
	/*
	 * 
	 * Removes an action from the action list
	 *   
	 * @param  string	$action		The action to be removed from the action list
	 * 								'all' for removing all the actions
	 * 
	 */
	
	function remove($action)
	{
		$action = strtolower($action);
		switch ($action){
			case 'all':
				$this->actions = array();
			break; 
			default:
				unset($this->actions[$action]);
			break;
		}
	}
	
	
	
	
	/*
	 * Reads the EXIF headers from JPEG images
	 * 
	 * @return	false/array		False for failure, or an associative array where the array indexes 
	 * 							are the header names and the array values are the values associated 
	 * 							with those headers.
	 * 
	 */
	
	public function getExifData()
	{
		if ($this->img['ext'] != $this->supportedTypes[IMAGETYPE_JPEG]){
			$this->setError($this->__("ERROR_CANNOT_READ_EXIF"));
			return false;	
		}
		$result = exif_read_data($this->getPath());
		if ($result == false){
			$this->setError($this->__("ERROR_CANNOT_READ_EXIF"));
			return false;
		}	
		
		return $result; 
	}
	
	
	
	
	/*
	 * 
	 * 
	 */
	
	private function getImageFromFile($path, $fileName)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				$function = '';
				switch($this->img['ext']){
					case 'jpg':
					case 'jpeg':
						$function = 'imagecreatefromjpeg';
					break;
					case 'png':
						$function = 'imagecreatefrompng';
					break;
					case 'gif':
						$function = 'imagecreatefromgif';
					break;
				}
				if ($function == '' || ! function_exists($function)){
					$this->setError($this->__("ERROR_INVALID_TYPE_GD"));
					return false;
				}
				
				if (! $this->temp = $function($this->img['path'])){
					$this->setError($this->__("ERROR_SAVE"));
					return false;
				}
				
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$this->temp = $path . 'jimglib--' . sha1(time().$path.$fileName).'.'.strtolower(substr($fileName,strrpos($fileName, '.') + 1));
				$this->temp_esc = escapeshellarg($this->temp);
				copy($this->img['path'], $this->temp);
			
			break;
		}
		
		return true;
	}
	
	
	
	
	/*
	 * 
	 * 
	 */
	
	private function saveImageToFile($path, $fileName, $quality, $display = false)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagealphablending($this->temp, true);
				imagesavealpha($this->temp, true);
				
				$saveFunction = '';
				switch(strtolower(substr($fileName,strrpos($fileName, '.') + 1))){
					case 'jpg':
					case 'jpeg':
						$saveFunction = 'imagejpeg';
					break;
					case 'png':
						$saveFunction = 'imagepng';
					break;
					case 'gif':
						$saveFunction = 'imagegif';
					break;
				}
		
				if ($saveFunction == '' || ! function_exists($saveFunction)){
					$this->setError($this->__("ERROR_INVALID_TYPE_GD"));
					return false;
				}
		
				$fullPath = $path . $fileName;
				if ($display == true){
					$fullPath = null;						
				}
				
				if ($saveFunction == 'imagejpeg') 
						 $message = $saveFunction($this->temp, $fullPath , $quality);
				else $message = $saveFunction($this->temp, $fullPath);
				
				if ($message == false){
					$this->setError($this->__("ERROR_SAVE"));
					return false;	
				}		
				
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				if ($display == true)
					$fullPath = $this->temp_esc;						
				else $fullPath = escapeshellarg($path . $fileName);
				
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				
				$command = $this->dir . $command . ' -quality '. $quality . '% ' . $this->temp_esc . ' '. $fullPath ;

				$message = exec(escapeshellcmd($command));

				if ($message != ''){
					$this->setError($this->__("ERROR_SAVE"));
					return false;	
				}
			break;
				
			
		}
		
		return true;	
	}
	
	
	
	
	/*
	 * 
	 * 
	 */
	
	private function removeTempImage()
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagedestroy($this->temp);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				unlink($this->temp);
				$this->temp = '';  
			break;
				
		}
		
	}
	
	
	
	
	/*
	 * Processes the requested actions.
	 *    
	 *    
	 * @param	string	$path			Path to the new image
	 * @param	string	$fileName		File name of the new image			
 	 * @param	int		$quality		Quality for saving JPGs
 	 * @param	boolean	$display		The image will be displayed directly to the browser or not
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	private function process($path, $fileName, $quality, $display = false)
	{

		$site_path = str_replace('\\', '/', realpath(JPATH_SITE)) . '/';
		$image_path = str_replace('\\', '/', $this->getPath());
		$image_path = $site_path . $image_path; 
			
		$_path = $image_path;
		$_fileName = basename($_path);
		$_path = str_replace('\\', '/', realpath(dirname($_path))). '/';

		
		if (! $this->getImageFromFile($_path, $_fileName)){
			return false;
		}

		if (count($this->actions['watermark']) > 0){
			$watermark = $this->actions['watermark'];
			unset($this->actions['watermark']);
		}
		
		$message = $this->executeActions();
		

		if ($message == true){
			if (count($watermark) > 0){
				$message = $this->watermark($watermark);
				if ($message == false){
					return false;
				}
			}
			if ($display == true){
				$extension = substr($fileName, strrpos($fileName, '.') + 1);
				switch (strtolower($extension)){
					case 'jpg':
					case 'jpeg':
						$header = 'Content-Type: image/jpeg';
					break;
					case 'png':
						$header = 'Content-Type: image/png';
					break;
					case 'gif':
						$header = 'Content-Type: image/gif';
					break;		
				}

				header($header);	
				
				if ($this->getImageLib() != $this->imgProcessors[0]){
					echo file_get_contents($this->temp);
				}
			}
			
			$message = $this->saveImageToFile($path, $fileName, $quality, $display);
		}
		
		$this->removeTempImage();

		return $message;
	}




	/*
	 * Executes actions to the temporary image
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	private function executeActions()
	{
		foreach ($this->actions as $action => $args){
			if (in_array($action, $this->filters) && !function_exists('imagefilter')) {
				$this->setError($this->__("ERROR_INVALID_FILTER_GD"));
				return false;
			}
			if (in_array($action, $this->filters) && !in_array($action, $this->filtersWithParams) ){
				if (! $this->$action()) return false;
			}
			else {
				if (! $this->$action($args)) return false;
			}
		}
		return true;
	}
	
	
	
	
	private function flip($direction)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				$width = imagesx($this->temp);
				$height = imagesy($this->temp);
				
				$new = imagecreatetruecolor($width, $height);
				
				if ($direction == 'v'){
					for ($i = 0; $i < $width; $i++){
						$message = imagecopy($new, $this->temp, $i, 0, $width - $i - 1, 0, 1, $height);
						if ($message == false) return false;
					}	
				}
				
				if ($direction == 'h'){
					for ($i = 0; $i < $height; $i++){
						$message = imagecopy($new, $this->temp, 0, $i, 0, $height - $i - 1, $width, 1);
						if ($message == false) return false;
					}	
				}
				
				imagedestroy($this->temp);
				$this->temp = $new;
						
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$direction = ($direction == 'h') ? ' -flip': ' -flop';
				
				$command = $this->dir . $command . $direction . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				} 
			break;
					
		}
				
		return true;
	}
	
	private function rotate($angle)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				if (! $this->temp = imagerotate($this->temp, 360-$angle, imagecolorallocate($this->temp, 255, 255, 255))){
					return false;
				}	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
								
				$command = $this->dir . $command . ' -rotate ' . escapeshellarg($angle) .  $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				} 
				
			break;
				
		}
		
		return true;
	}
	
	
	private function resize($args)
	{		
				
	switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				$originalWidth = imagesx($this->temp);
				$originalHeight = imagesy($this->temp);
				
				$width = min($originalWidth, $args['width']);
				$height = min($originalHeight, $args['height']);
				
				$srcX = $srcY = $destX = $destY = 0;
				$newWidth = $width;
				$newHeight = $height;
				
				switch ($args['option']){
					case 'bestfit':
						if ($width == 0)  $newWidth = $width  = round($originalWidth * $height / $originalHeight);
						if ($height == 0) $newHeight = $height = round($originalHeight * $width / $originalWidth);
						if (($originalWidth / $width) > ($originalHeight / $height))
							$height = $newHeight = round($originalHeight * $width / $originalWidth);
						else $width = $newWidth  = round($originalWidth * $height / $originalHeight);	
					break;
					case 'crop':
						if (($originalWidth / $width) > ($originalHeight / $height)){
							$aux = $originalWidth;
							$originalWidth = $width * $originalHeight / $height;
							$srcX = ($aux - $originalWidth) / 2;
						}
						else {
							$aux = $originalHeight;
							$originalHeight = $height * $originalWidth / $width;
							$srcY = ($aux - $originalHeight) / 2;
						}
					break;	
					case 'stretch':
						if ($width == 0)  $newWidth = $width  = $originalWidth;
						if ($height == 0) $newHeight = $height = $originalHeight;
					break;
					case 'fill':
						if (($originalWidth / $width) > ($originalHeight / $height)){
							$newHeight = round($originalHeight * $width / $originalWidth);
							$destY = ($height - $newHeight) / 2;
						}
						else {
							$newWidth  = round($originalWidth * $height / $originalHeight);
							$destX = ($width - $newWidth) / 2;
						}
					break;
				}

				$new = imagecreatetruecolor($width, $height);
				if ($args['option'] == "fill") {
					$rgb = $this->getColor($args['color']);
					$color = imagecolorallocate($new, $rgb[0], $rgb[1], $rgb[2]);
					imagefill($new, 0, 0, $color);
				}
				if (! imagecopyresampled($new, $this->temp, $destX, $destY, $srcX, $srcY, $newWidth, $newHeight, $originalWidth, $originalHeight)){
					return false;
				}
				
				imagedestroy($this->temp);
				$this->temp = $new;
		
		
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				if ($args['width'] == 0) $dimensions = 'x'.$args['height'];
				else if ($args['height'] == 0) $dimensions = $args['width'];
				else $dimensions = $args['width'].'x'.$args['height'];
				
				switch ($args['option']){
						case 'bestfit':
							$command = $this->dir . $base_command . ' -resize ' . escapeshellarg($dimensions) . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
							$message = exec(escapeshellcmd($command));	
						break;
						case 'crop':
							$srcX = $srcY = 0;
							$originalWidth = $this->img['width'];
							$originalHeight = $this->img['height'];
							
							if (($originalWidth / $args['width']) > ($originalHeight / $args['height'])){
								$aux = $originalWidth;
								$originalWidth = $args['width'] * $originalHeight / $args['height'];
								$srcX = ($aux - $originalWidth) / 2;
								$dimensions = 'x'.$args['height'];
							}
							else {
								$aux = $originalHeight;
								$originalHeight = $args['height'] * $originalWidth / $args['width'];
								$srcY = ($aux - $originalHeight) / 2;
								$dimensions = $args['width'];
							}
							
							// Resize the image with the master dimension
							
							$command = $this->dir . $base_command . ' -resize ' . escapeshellarg($dimensions) . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
							$message = exec(escapeshellcmd($command));	
							
							// And then crop it to the right dimensions
							
							$command = $this->dir . $base_command . ' -crop ' . escapeshellarg($args['width'] . 'x' . $args['height'] . '+' . $srcX . '+' . $srcY ). ' ' . $this->temp_esc . ' ' . $this->temp_esc;
							$message = exec(escapeshellcmd($command));	
						break;	
						case 'stretch':
							if ($args['width'] == 0) $dimensions = $this->img['width'].'x'.$args['height'];
							else if ($args['height'] == 0) $dimensions = $args['width'].'x'.$this->img['height'];
							else $dimensions = $args['width'].'x'.$args['height'];
							
							$command = $this->dir . $base_command . ' -resize ' . escapeshellarg($dimensions . '!') . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
							$message = exec(escapeshellcmd($command));	
						break;
						case 'fill':
							if ($args['color'][0] != '#') $args['color'] = '#' . $args['color'];
							
							$temp_fill = '___fill_' . sha1(time().'___fill') . '.jpg';
							
							$command = $this->dir . $base_command . ' -size ' . escapeshellarg($dimensions) . ' xc:"'. $args['color'] . '" '. $temp_fill;
							$message = exec($command);	
							
							$command = $this->dir . $base_command . ' -resize ' . escapeshellarg($dimensions) . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
							$message = exec(escapeshellcmd($command));	
							
							$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'composite'.$this->ext : 'gm'.$this->ext . ' composite' ;
							$command = $this->dir . $base_command  . ' -gravity center over ' . $this->temp_esc . ' ' . $temp_fill . ' ' . $this->temp_esc;
							$message = exec(escapeshellcmd($command));	
							
							unlink($temp_fill);
						break;
						if ($message != ''){
							return false;	
						} 
					} 
			break;
				
		}		
		
		return true;
	}
	
	
	
	private function crop($args)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				$originalWidth = imagesx($this->temp);
				$originalHeight = imagesy($this->temp);
				
				$args['width']  = min($args['width'], $originalWidth);
				$args['height'] = min($args['height'], $originalHeight);
			
				$new = imagecreatetruecolor($args['width'], $args['height']);
				if (! imagecopyresampled($new, $this->temp, 0, 0, $args['top'], $args['left'], $originalWidth, $originalHeight, $originalWidth, $originalHeight)){
					return false;
				}
				
				imagedestroy($this->temp);
				$this->temp = $new;
				
			break;

			case $this->imgProcessors[1]: 			
			case $this->imgProcessors[2]: 
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				
				$originalWidth = $this->img['width'];
				$originalHeight = $this->img['height'];
							
				$args['width']  = min($args['width'], $originalWidth);
				$args['height'] = min($args['height'], $originalHeight);

				$command = $this->dir . $base_command . ' -crop ' . escapeshellarg($args['width'] . 'x' . $args['height'] . '+' . $args['top'] . '+' . $args['left'] ). ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));	
				
			break;
				
		}
		return true;
	}
	
	private function watermark($args)
	{
		$path = JPATH_SITE . '/' . $args['watermark'];
		
		$position = $args['position'];
		if ($position == 'random'){
			$rand = rand(0, count($this->watermarkPositions) - 1);
			$position = $this->watermarkPositions[$rand - 1];	
		}

		/*
		 * @TODO : Implement transparency feature
		 * 
		 */
			
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				$wm = imagecreatefrompng($path);
				
				$width = imagesx($this->temp);
				$height = imagesy($this->temp);
						
				// Gets the watermark info
				$img_info = getimagesize($path);
				$wmWidth = $img_info[0];
				$wmHeight = $img_info[1];
				
				$destX = $destY = $srcX = $srcY = 0;
								
				switch ($position){
					case 'center':
						$destX = $width / 2 - $wmWidth / 2;
						$destY = $height / 2 - $wmHeight / 2;
					break;
					case 'top':
						$destX = $width / 2 - $wmWidth / 2;
					break;
					case 'topleft':
					break;
					case 'topright':
						$destX = $width - $wmWidth;
					break;
					case 'bottom':
						$destX = $width / 2 - $wmWidth / 2;
						$destY = $height - $wmHeight;
					break;
					case 'bottomleft':
						$destY = $height - $wmHeight;
					break;
					case 'bottomright':
						$destX = $width - $wmWidth;
						$destY = $height - $wmHeight;
					break;
					case 'right':
						$destX = $width - $wmWidth;
						$destY = $height / 2 - $wmHeight / 2;
					break;
					case 'left':
						$destY = $height / 2 - $wmHeight / 2;
					break;
				}
						
				imagecopy($this->temp, $wm, $destX, $destY, $srcX, $srcY, $wmWidth, $wmHeight);
				
				imagedestroy($wm);
				
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'composite'.$this->ext : 'gm'.$this->ext . ' composite' ;
				
				switch ($position){
					case 'top': $position = 'north';
					break;
					case 'topleft': $position = 'northwest';
					break;
					case 'topright': $position = 'northeast';
					break;
					case 'bottom': $position = 'south';
					break;
					case 'bottomleft': $position = 'southwest';
					break;
					case 'bottomright': $position = 'southeast';
					break;
					case 'right': $position = 'east';
					break;
					case 'left': $position = 'west';
					break;
				}
				
				$path = str_replace('\\', '/', realpath($path));
				
				$command = $this->dir . $base_command  . ' -gravity '. $position .' '. escapeshellarg($path) .' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));	
			break;
				
		}
		
		return true;
	}
	
	
	private function grayscale()
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_GRAYSCALE);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
							
				$command = $this->dir . $command . ' -colorspace Gray' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				} 
			break;
				
		}
				
		return true;
	}
	
	
	private function sepia()
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_GRAYSCALE);
				imagefilter($this->temp, IMG_FILTER_COLORIZE, 100, 50, 0);
			break;

			case $this->imgProcessors[1]:
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
							
				$command = $this->dir . $base_command . ' -colorspace Gray' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				$command = $this->dir . $base_command . ' -sepia-tone 80%' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec($command);
				
				if ($message != ''){
					return false;	
				}  
			break;
			case $this->imgProcessors[2]:

				$this->setError($this-> __("ERROR_SEPIA_NOT_SUPPORTED_GM"));
				return false;	
				   
			break;				
				
		}
				
		return true;
	}
	
	private function negative()
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_NEGATE);			
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$command = $this->dir . $command . ' -negate' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				}    
			break;
				
		}
		
		return true;
	}
	
	private function blur()
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_GAUSSIAN_BLUR);
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$command = $this->dir . $command . ' -blur 1' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				}    
			break;
				
		}
		
		return true;
	}
	
	private function invert()
	{
		return $this->negative();
	}
	
	
	private function edgedetect()
	{
		switch ($this->getImageLib()){

			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_EDGEDETECT);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$command = $this->dir . $command . ' -edge 1' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				}    
			break;
							
		}
		
		return true;
	}
	
	
	private function meanremoval()
	{
		switch ($this->getImageLib()){

			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_MEAN_REMOVAL);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$this->setError($this-> __("ERROR_MEAN_NOT_SUPPORTED"));
				return false;	 
			break;
				
		}
				
		return true;
	}
	
	
	private function emboss()
	{
		switch ($this->getImageLib()){

			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_EMBOSS);	
			break;
		
			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$command = $this->dir . $command . ' -emboss 1 -negate' . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				}    
			break;
				
		}
		
		
		return true;
	}
	
	
	/*
	 * Thanks to www.partdigital.com  and  
	 * Nakul Ganesh, Joomla! GSoC 2008 (http://developer.joomla.org/gsoc2008/advanced-media-manager.html)
	 * 
	 */
	
	private function dropshadow()
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				
				$x = imagesx($this->temp);
				$y = imagesy($this->temp);
							 	 
				$dir = str_replace('\\', '/', realpath(JPATH_SITE . DS . JImageLib::DEFAULT_DROPSHADOW_DIRECTORY)."/");
				
				$tl = imagecreatefromgif($dir."shadow_TL.gif");
				$t  = imagecreatefromgif($dir."shadow_T.gif"); 
				$tr = imagecreatefromgif($dir."shadow_TR.gif"); 
				$r  = imagecreatefromgif($dir."shadow_R.gif"); 
				$br = imagecreatefromgif($dir."shadow_BR.gif"); 
				$b  = imagecreatefromgif($dir."shadow_B.gif"); 
				$bl = imagecreatefromgif($dir."shadow_BL.gif");
				$l  = imagecreatefromgif($dir."shadow_L.gif");
				
						
				$w = imagesx($l); 	
				$h = imagesy($l);	
			
				$newWidth  = $x + (2*$w);
				$newHeight = $y + (2*$w); 
				
					
				$new = imagecreatetruecolor($newWidth, $newHeight); 
					 
				imagecopyresized($new, $t, 0, 0, 0, 0, $newWidth, $w, $h, $w);			
				imagecopyresized($new, $l, 0, 0, 0, 0, $w, $newHeight, $w, $h);
				imagecopyresized($new, $b, 0, $newHeight-$w, 0, 0, $newWidth, $w, $h, $w); 
				imagecopyresized($new, $r, $newWidth-$w, 0, 0, 0, $w, $newHeight, $w, $h);
						 
				$w = imagesx($tl); 
				$h = imagesy($tl); 
				imagecopyresized($new, $tl, 0, 0, 0, 0, $w, $h, $w, $h);  
				imagecopyresized($new, $bl, 0, $newHeight-$h, 0, 0, $w, $h, $w, $h); 
				imagecopyresized($new, $br, $newWidth-$w, $newHeight-$h, 0, 0, $w, $h, $w, $h);
				imagecopyresized($new, $tr, $newWidth-$w, 0, 0, 0, $w, $h, $w, $h);  
						 
					
				$w = imagesx($l); 
				imagecopyresampled($new, $this->temp, $w, $w, 0, 0, $x, $y, $x ,$y);
				$this->temp = $new;

			break;

			case $this->imgProcessors[1]: 
				
				
				$dir = str_replace('\\', '/', realpath(JPATH_SITE . DS . JImageLib::DEFAULT_DROPSHADOW_DIRECTORY)."/");
				
				$tl = escapeshellarg($dir."shadow_TL.gif");
				$t  = escapeshellarg($dir."shadow_T.gif"); 
				$tr = escapeshellarg($dir."shadow_TR.gif"); 
				$r  = escapeshellarg($dir."shadow_R.gif"); 
				$br = escapeshellarg($dir."shadow_BR.gif"); 
				$b  = escapeshellarg($dir."shadow_B.gif"); 
				$bl = escapeshellarg($dir."shadow_BL.gif");
				$l  = escapeshellarg($dir."shadow_L.gif");
				$bb  = escapeshellarg($dir."blank.jpg");
				
				$temp_fill = '___fill_' . sha1(time().'___fill') . '.jpg';
				$temp_top = '___t_' . sha1(time().'___t') . '.jpg';
				$temp_right = '___r_' . sha1(time().'___r') . '.jpg';
				$temp_left = '___l_' . sha1(time().'___l') . '.jpg';
				$temp_bottom = '___b_' . sha1(time().'___b') . '.jpg';
				$temp_bg = '___bg_' . sha1(time().'___bg') . '.jpg';
				
				$img_info = getimagesize($this->temp);
				$width = $img_info[0];
				$height = $img_info[1];
				
				$base_command = 'convert'.$this->ext;
				
				$message = exec(escapeshellcmd($base_command . ' -resize '.$width.'x15! ' . $t . ' ' . $temp_top));
				$message = exec(escapeshellcmd($base_command . ' -resize 15x'.$height.'! ' . $l . ' ' . $temp_left));
				$message = exec(escapeshellcmd($base_command . ' -resize 15x'.$height.'! ' . $r . ' ' . $temp_right));
				$message = exec(escapeshellcmd($base_command . ' -resize '.$width.'x15! ' . $b . ' ' . $temp_bottom));
				$message = exec(escapeshellcmd($base_command . ' -resize '.($width + 20).'x'.$height.'! ' . $bb . ' ' . $temp_bg));
				
				$base_command = 'montage'.$this->ext;
				$command = $this->dir . $base_command  
						. ' -gravity northwest '.$tl
						. ' -gravity north "'.$temp_top.'" '
						. ' -gravity northeast '.$tr 
						. ' -geometry +0+0 '.$temp_top.' ';
				$message = exec(escapeshellcmd($command));
						
				$command = $this->dir . $base_command
						. ' -gravity northwest "'.$temp_left.'" '
						. ' -gravity north "'.$temp_bg.'" '
						. ' -gravity northeast "'.$temp_right.'" '
						. ' -gravity southwest '.$bl
						. ' -gravity south "'.$temp_bottom.'" '
						. ' -gravity southeast '.$br
						. ' -tile 3x2 -geometry +0+0 '.$temp_fill.' ';
					
				$message = exec(escapeshellcmd($command));
				
				
				$command = $this->dir . $base_command  
						. ' -gravity north "'.$temp_top.'" '
						. ' -gravity south '.$temp_fill 
						. ' -tile 1x2 -geometry +0+0 '.$temp_fill.' ';
				$message = exec(escapeshellcmd($command));
				
					
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'composite'.$this->ext : 'gm'.$this->ext . ' composite' ;
				$command = $this->dir . $base_command  . ' -gravity center over ' . $this->temp_esc . ' ' . $temp_fill . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				unlink($temp_fill);
				unlink($temp_top);
				unlink($temp_left);
				unlink($temp_right);
				unlink($temp_bottom);
				unlink($temp_bg);
			break;
			case $this->imgProcessors[2]:
				$base_command = 'gm'.$this->ext . ' montage' ;
				
				$dir = str_replace('\\', '/', realpath(JPATH_SITE . DS . JImageLib::DEFAULT_DROPSHADOW_DIRECTORY)."/");
				
				$tl = escapeshellarg($dir."shadow_TL.gif");
				$t  = escapeshellarg($dir."shadow_T.gif"); 
				$tr = escapeshellarg($dir."shadow_TR.gif"); 
				$r  = escapeshellarg($dir."shadow_R.gif"); 
				$br = escapeshellarg($dir."shadow_BR.gif"); 
				$b  = escapeshellarg($dir."shadow_B.gif"); 
				$bl = escapeshellarg($dir."shadow_BL.gif");
				$l  = escapeshellarg($dir."shadow_L.gif");
				$bb  = escapeshellarg($dir."blank.jpg");
				
				$temp_fill = '___fill_' . sha1(time().'___fill') . '.jpg';
				
				$img_info = getimagesize($this->temp);
				$width = $img_info[0];
				$height = $img_info[1];
				
				$command = $this->dir . $base_command  
						. ' -gravity northwest '.$tl
						. ' convert -resize '.$width.'x15! -gravity north '.$t
						. ' -gravity northeast '.$tr
						. ' convert -resize 15x'.$height.'! -gravity west '.$l
						. ' convert -resize '.($width + 20).'x'.$height.'! '.$bb
						. ' convert -resize 15x'.$height.'! -gravity east '.$r
						. ' -gravity southwest '.$bl
						. ' convert -resize '.$width.'x15! -gravity south '.$b
						. ' -gravity southeast '.$br
						. ' -tile 3x3 -geometry +0+0 '. $temp_fill .' ';
					
				$message = exec(escapeshellcmd($command));
					
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'composite'.$this->ext : 'gm'.$this->ext . ' composite' ;
				$command = $this->dir . $base_command  . ' -gravity center over ' . $this->temp_esc . ' ' . $temp_fill . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
					
				unlink($temp_fill);
			break;
				
		}
		
		return true;
	}
	
	private function brightness($brightness)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_BRIGHTNESS, $brightness);
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$command = $this->dir . $command . ' -modulate ' . ($brightness + 100) .' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				}    
			break;	
		}
		
		return true;
	}
	
	private function contrast($contrast)
	{	
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_CONTRAST, $contrast);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]: 
				$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				
				if ($contrast < 0){
					$contrast_command = ' +contrast';
					$contrast = - $contrast;
				}
				else $contrast_command = ' -contrast';
				
				$contrast = ceil($contrast / 10);
				/*
				 * The -contrast command increases the image contrast by 10%, so it has to be repeated
				 * by ceil($contrast / 10) times
				 */
				
				$command = ' ';
				for ($i = 0; $i < $contrast; $i++)
					$command .= $contrast_command;
					
				$command = $this->dir . $base_command . $command . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec(escapeshellcmd($command));
				
				if ($message != ''){
					return false;	
				}    
			break;
				
		}
		
		return true;
	} 
	
	
	private function smoothness($smoothness)
	{
	
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_SMOOTH, $smoothness);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$this->setError($this-> __("ERROR_SMOOTH_NOT_SUPPORTED"));
				return false;	 
			break;
				
		}
		
		return true;
	}
	
	
	private function colorize($args)
	{
		switch ($this->getImageLib()){
			
			case $this->imgProcessors[0]:
				imagefilter($this->temp, IMG_FILTER_COLORIZE, $args['r'], $args['g'], $args['b']);	
			break;

			case $this->imgProcessors[1]: 
			case $this->imgProcessors[2]:
				$command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
				$separator = ($this->getImageLib() == $this->imgProcessors[1]) ? ',' : '/' ;
				$command = $this->dir . $command . ' -colorize ' . $args['r'] . $separator . $args['g']. $separator . $args['b'] . ' ' . $this->temp_esc . ' ' . $this->temp_esc;
				$message = exec($command);
				
				if ($message != ''){
					return false;	
				}     
			break;
				
		}
		
		return true;
	}


	/*
	 * Saves changes of the current image. A new image is created if path is not empty
	 * 
	 * @param	string		$path		Path to the new image
	 * @param	int			$quality	Saving quality(only for JPEGs)
	 * 
	 * @return  false or string			Returns false on failure and the path to the saved image on succes
	 * 
	 */
	
	function save($path = '', $quality = JImageLib::DEFAULT_JPG_QUALITY)
	{	
		if (!is_int($quality) || $quality < 0 || $quality > 100 ){
				$this->setError($this-> __("ERROR_INVALID_QUALITY_PARAM"));
				return false;
			}
		if (!isset($this->img) || count($this->img) < 1){
			$this->setError($this-> __("ERROR_NO_IMAGE"));
			return false;
		}
		if (!isset($this->imageLib)){
			$this->setImageLib();
		}

		if (($this->getWidth() != 0 || $this->getHeight() != 0 ) && (! array_key_exists('resize', $this->actions) && ! array_key_exists('crop', $this->actions))){
			$this->setResizing();
		}
		
		if ($path == '') {
			$path = $this->getPath();			
		}	
		if (file_exists($path)){
			clearstatcache();
			if (filemtime($path) + $this->getCacheTime() > time()){
				return $path;
			}
			
		}
		
		$tmp = str_replace('\\', '/', dirname($path));
		
		if (! file_exists($tmp)){
			if (!mkdir($tmp)){
				$this->setError($this-> __("ERROR_INVALID_DIRECTORY"));
				return false;
			}
		}
		
		
		$tmp = str_replace('\\', '/', realpath($tmp)). '/';
				
		if (! is_writable($tmp)){
			$this->setError($this-> __("ERROR_INVALID_DIRECTORY"));
			return false;
		}
		
		$fileName = basename($path);
		$path = str_replace('\\', '/', realpath(dirname($path))). '/';
		
				
		$message = $this->process($path, $fileName, $quality);

		if ($message == false){
			return false;
		}	
		else {
			// Refresh image information in case of override
			$site_path = str_replace('\\', '/', realpath(JPATH_SITE)) . '/';
			$new_path = str_replace($site_path, '', $path.$fileName); 
			if ($path.$fileName == str_replace('\\', '/', realpath($this->getPath())) ){
				$this->setPath($new_path);
			}
			return $new_path;
		}	 
	}
	
	
	
	
	/*
	 * Saves changes of the current image. A new image is created if path is not empty
	 * 
	 * @return  false or string			Returns false on failure and the path to the generated image on succes
	 *  
	 */
	
	function getThumbnail()
	{	
		// Sets the naming options
		
		$width = min($this->getWidth(), $this->img['width']);
		$height = min($this->getHeight(), $this->img['height']);
		if ($width == 0)  $width  = $this->img['width'];
		if ($height == 0) $height = $this->img['height'];

		
		if (isset($this->customName) && $this->getName() != ''){
			$path = dirname($this->getName()) . '/';
			$fileName = basename($this->getName());
		}
		else {
			$fileName = basename($this->getPath());
			$mode = $this->getUseImageSize();	
			if ($mode == 'both' || $mode == 'file'){
				$fileName = $width . "x". $height. "_". $fileName;
			}
			if (isset($this->prefix) && $this->getPrefix() != ''){
				$fileName = $this->getPrefix() . $fileName;
			}
		

			if (isset($this->directory) && $this->getDirectory() != ''){
				$path = $this->getDirectory();
			}
			else {
				$path = dirname($this->getPath()) . '/';			
			}
			
			$mode = $this->getUseImageSize();
			if ($mode == 'both' || $mode == 'dir'){
					$path = $path . "/" . $width . "x". $height . "/";
			}
		}
		
		
		$this->setResizing();
			
		$message = $this->save($path.$fileName);
		
		return $message;		
	}
	
	
	
	
	/*
	 * Outputs the image to the browser with the appropriate headers
	 * 
	 */
	
	function getImage()
	{	
		if (!isset($this->img) || count($this->img) < 1){
			$this->setError($this-> __("ERROR_NO_IMAGE"));
			return false;
		}
		if (!isset($this->imageLib)){
			$this->setImageLib();
		}
		
		if (($this->getWidth() || $this->getHeight()) && (! array_key_exists('resize', $this->actions) && ! array_key_exists('crop', $this->actions))){
			$this->setResizing();
		}
		
		$path = $this->getPath();
		
		$fileName = basename($path);
		
		$path = str_replace('\\', '/', realpath(dirname($path))). '/';
		

		
		$message = $this->process($path, $fileName, 100, true);
		
				
		return $message;		
	}
	
	
	
	
	/*
	 * Creates a JImageLib object from a text (used for watermarking)
	 * 
	 * @param	string		$text			The text to write
	 * @param	string		$font_family	Font family for the text
	 * @param	int			$font_size		Font size
	 * @param	string		$font_color		The color for the text (hex code).
	 * 
	 * @return	false or string				Returns false on failure and the new object on succes
	 * 
	 */
	
	public function getImageText($text, $font_family = JImageLib::DEFAULT_WM_FONT_FAMILY, $font_size = JImageLib::DEFAULT_WM_FONT_SIZE, $font_color = JImageLib::DEFAULT_WM_FONT_COLOR)
	{
			if (!is_int($font_size) || $font_size < 0 || $font_size > 100){
				$this->setError($this->__("ERROR_INVALID_WM_FONT_SIZE"));
				return false;
			}
			if (! $this->getColor($font_color)){
				$this->setError($this->__("ERROR_INVALID_WM_FONT_COLOR"));
				return false;
			}
			
			$img = new JImageLib();
			$path = $img->getDirectory() . sha1(time().$text) . '.png';
			
			$font = JImageLib::DEFAULT_FONT_DIRECTORY . $font_family . '.ttf';
			
			// Set some dimensions for the image
			$size = imageTTFBBox($font_size, 0, $font, $text);
			$x = abs($size[2]) + abs($size[0]);
			$y = abs($size[7]) + abs($size[1]) + 5;
					
			switch ($this->getImageLib()){
			
				case $this->imgProcessors[0]:

					$im = imagecreatetruecolor($x, $y);
					
					imagesavealpha($im, true);
					imagealphablending($im, false);

					// Creatrs the transparent background
					$bg = imagecolorallocatealpha($im, 220, 220, 220, 127);
					imagefill($im, 0, 0, $bg);
		

					// Create color resource for the text
					$rgb = $this->getColor($font_color); 
					$color = imagecolorallocate($im, $rgb[0], $rgb[1], $rgb[2]);
									
					// Add the text
					imagettftext($im, $font_size, 0, 0, $y-5 , $color, $font, $text);
					
					imagepng($im, $path);
				break;
				
				case $this->imgProcessors[1]:
				case $this->imgProcessors[2]:
					$tmp_path1 = $img->getDirectory() . sha1(time().$text) . '_1.png';
					$tmp_path2 = $img->getDirectory() . sha1(time().$text) . '_2.png';
					
					// The color code must have the '#' char
					if ($font_color[0] != '#') $font_color = '#' . $font_color;
					
					$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'convert'.$this->ext : 'gm'.$this->ext . ' convert' ;
								
					$command = $this->dir . $base_command . ' -size ' . $x. 'x' . $y . ' xc:grey30 -font ' . $font_family 
							. ' -pointsize ' . $font_size . ' -gravity center -draw "fill \"' . $font_color . '\" '
							. ' text 0,0 \'' . $text . '\' " ' . $tmp_path1;
					$message = exec($command);
					
					$command = $this->dir . $base_command . ' -size ' . $x. 'x' . $y . ' xc:black -font ' . $font_family 
							. ' -pointsize ' . $font_size . ' -gravity center -draw "fill white '
							. ' text 0,0 \'' . $text . '\' " +matte ' . $tmp_path2;
					$message = exec($command);
					
					$base_command = ($this->getImageLib() == $this->imgProcessors[1]) ? 'composite'.$this->ext : 'gm'.$this->ext . ' composite' ;
					$command = $this->dir . $base_command . ' -compose CopyOpacity ' . $tmp_path2 . ' ' . $tmp_path1 . ' ' .$path;
					$message = exec($command);
					
					
					unlink($tmp_path1);
					unlink($tmp_path2);
					if ($message != ''){
						return false;	
					}  
				break;
			}
			
			$site_path = str_replace('\\', '/', realpath(JPATH_SITE)) . '/';
			$path = str_replace('\\', '/', realpath($path));
			$path = str_replace($site_path, '', $path); 	
			
			if (! $img->setPath($path)){
				return false;
			}
			
			return $img;
	}
	
	
	
	
	/*
	 * Creates a copy of the image with a watermark image or text applied on it, to a specified position
	 * 
	 * The image used as a watermark must be PNG
	 *
	 * @param	string 				$watermark		Path to the watermark image
	 * @param	string				$position		The position for the Watermark
	 * 		Options available: "center", "top", "topright", "topleft", "bottom", "bottomright", 
	 * 		"bottomleft", "right", "left" or "random" 
	 * @param	int					$margin_top		Value for top margin
	 * @param	int					$margin_left	Value for left margin
	 * @param	int					$transparency	Value for watermark transparency
	 * 
	 * @return  false or string			Returns false on failure and the path to the generated image on succes
	 *  
	 */
	
	function addWatermark($watermark, $position = JImageLib::DEFAULT_WM_POSITION, $margin_top = JImageLib::DEFAULT_WM_MARGIN_TOP, $margin_left = JImageLib::DEFAULT_WM_MARGIN_LEFT, $transparency = JImageLib::DEFAULT_WM_TRANSPARENCY)
	{	
		// Checks if params are correct
		$path = $watermark;
		$path = JPATH_SITE . DS . $path;
		if (!is_file($path)) {
				$this->setError($this->__("ERROR_WM_FILE_NOT_FOUND"));
				return false;
			}
			
		$img_info = getimagesize($path);
		if ((!is_array($img_info)) OR (count($img_info) < 3)){
			$this->setError($this-> __("ERROR_INVALID_WM_FILE"));
			return false;
		}
				
		if($img_info[2] != IMAGETYPE_PNG){
			$this->setError($this-> __("ERROR_INVALID_WM_TYPE"));
			return false;
		}
		
		if (! in_array(strtolower($position), $this->watermarkPositions)){
			$this->setError($this-> __("ERROR_INVALID_WM_POSITION"));
			return false;
		}
		
		if (!is_int($margin_top) || $margin_top < 0){
			$this->setError($this->__("ERROR_INVALID_MARGIN_TOP"));
			return false;
		}
		
		if (!is_int($margin_left) || $margin_left < 0){
			$this->setError($this->__("ERROR_INVALID_MARGIN_LEFT"));
			return false;
		}
		
		if (!is_int($transparency) || $transparency < 0 || $transparency > 100){
			$this->setError($this->__("ERROR_INVALID_WM_TRANSPARENCY"));
			return false;
		}
		
	
		// Sets the naming options
		$width = min($this->getWidth(), $this->img['width']);
		$height = min($this->getHeight(), $this->img['height']);
		if ($width == 0)  $width  = $this->img['width'];
		if ($height == 0) $height = $this->img['height'];
		
		
		if (isset($this->customName) && $this->getName() != ''){
			$path = dirname($this->getName()) . '/';
			$fileName = basename($this->getName());
		}
		else {
			$fileName = basename($this->getPath());
			$mode = $this->getUseImageSize();	
			if ($mode == 'both' || $mode == 'file'){
				$fileName = $width . "x". $height. "_". $fileName;
			}
			if (isset($this->prefix) && $this->getPrefix() != ''){
				$fileName = $this->getPrefix() . $fileName;
			}
		

			if (isset($this->directory) && $this->getDirectory() != ''){
				$path = $this->getDirectory();
			}
			else {
				$path = dirname($this->getPath()) . '/';	
			}
		
			$mode = $this->getUseImageSize();
			if ($mode == 'both' || $mode == 'dir'){
					$path = $path . "/" . $width . "x". $height . "/";
			}
		}
		
		$this->actions['watermark'] = array('watermark' => $watermark, 'position' => strtolower($position), 
								'margin_top' => $margin_top, 'margin_left' => $margin_left, 'transparency' => $transparency,
								'font_family' => $font_family, 'font_size' => $font_size, 'font_color' => $font_color);
		
		
		$message = $this->save($path.$fileName);
		
			
		return $message;		
	}
	
	
	
	
	/*
	 * Creates a copy of the image with a watermark text applied on it, to a specified position
	 * 
	 * The image used as a watermark must be PNG
	 *
	 * @param	string		$text			The text to write
	 * @param	string		$font_family	Font family for the text
	 * @param	int			$font_size		Font size
	 * @param	string		$font_color		The color for the text (hex code).
	 * @param	string				$position		The position for the Watermark
	 * 		Options available: "center", "top", "topright", "topleft", "bottom", "bottomright", 
	 * 		"bottomleft", "right", "left" or "random" 
	 * @param	int					$margin_top		Value for top margin
	 * @param	int					$margin_left	Value for left margin
	 * @param	int					$transparency	Value for watermark transparency
	 * 
	 * @return  false or string			Returns false on failure and the path to the generated image on succes
	 *  
	 */
	
	function addWatermarkText($text, $font_family = JImageLib::DEFAULT_WM_FONT_FAMILY, $font_size = JImageLib::DEFAULT_WM_FONT_SIZE, $font_color = JImageLib::DEFAULT_WM_FONT_COLOR, $position = JImageLib::DEFAULT_WM_POSITION, $margin_top = JImageLib::DEFAULT_WM_MARGIN_TOP, $margin_left = JImageLib::DEFAULT_WM_MARGIN_LEFT, $transparency = JImageLib::DEFAULT_WM_TRANSPARENCY)
	{	
		// Gets the text image
		$text_image = $this->getImageText($text, $font_family, $font_size, $font_color);
		if ($text_image == false){
			return false;
		}
		
		$site_path = str_replace('\\', '/', realpath(JPATH_SITE)) . '/';
		$watermark = str_replace('\\', '/', realpath($text_image->getPath()));
		$watermark = str_replace($site_path, '', $watermark);
		 	
		$message = $this->addWatermark($watermark, $position, $margin_top, $margin_left, $transparency);
		
		// Delete the image
		unlink($text_image->getPath());
		
		return $message;
	}	
	
	
	
	
	/*
	 * Generates a HTML <IMG /> tag with all the attributes
	 * If width and height are different from the image's dimensions,
	 * the tag will consist in a thumbnail linked by the image
	 * using the selected pop-up type
	 * 
	 * @return		string		String representing <IMG /> tag.
	 * 
	 */
	
	function getTag()
	{
		$width = $this->getWidth();
		$height = $this->getHeight();
		
		/* 
		 * If one of the length property is set, saves the image without resizing it
		 * and then generates its thumbnail
		 * 
		 */
		
		if ($width || $height) {
			$this->setWidth(0);	
			$this->setHeight(0);
			unset($this->actions['resizing']);
		}
		 
		if (! $image = $this->save()){
			return false;
		}
		
		
		$thumb = '';
		if ($width || $height) {
			$this->setWidth($width);
			$this->setHeight($height);
			if (! $thumb = $this->getThumbnail()){
				return false;
			}
		}
		$attr = "";
		
		if ($this->getClass() != '') $attr .= ' class="'. $this->getClass() .'" ';
		if ($this->getTitle() != '') $attr .= ' title="'. $this->getTitle() .'" ';
		if ($this->getId() != '') $attr .= ' id="'. $this->getId() .'" ';
		
		if ($thumb != ''){   // if a thumbnail was generated
		
			$img = JHTML::image($thumb, $this->getAlt(), $attr . $this->getAttributes());
	
			$document = &JFactory::getDocument();
			
			if ($this->getPopUp() == 'slimbox'){
				$document->addStyleSheet(JURI::root() . JImageLib::SLIMBOX_CSS_PATH.'slimbox.css');
				//$document->addScript(JURI::root() . JImageLib::SLIMBOX_JS_PATH.'mootools.js');
				$document->addScript(JURI::root() . JImageLib::SLIMBOX_JS_PATH.'slimbox.js');
				$tag = JHTML::link(JURI::root() . $image, $img, ' rel="lightbox" title="'.$this->getTitle().'" ');			
			}
			
			if ($this->getPopUp() == 'greybox'){
				$document->addStyleSheet(JURI::root() . JImageLib::GREYBOX_CSS_PATH .'gb_styles.css');
				$document->addScript(JURI::root() . JImageLib::GREYBOX_JS_PATH .'path.js');
				$document->addScript(JURI::root() . JImageLib::GREYBOX_JS_PATH .'AJS.js');
				$document->addScript(JURI::root() . JImageLib::GREYBOX_JS_PATH .'AJS_fx.js');
				$document->addScript(JURI::root() . JImageLib::GREYBOX_JS_PATH .'gb_scripts.js');
				$tag = JHTML::link(JURI::root() . $image, $img, ' rel="gb_image[]" title="'.$this->getTitle().'" ');
			}
			
			if ($this->getPopUp() == 'none'){
				$tag = JHTML::link($image, $img, ' title="'.$this->getTitle().'" ');
			}		
			
		}
		else $tag = JHTML::image($image, $this->getAlt(), $attr . $this->getAttributes());
				
		return $tag;
	}
	
	

	
	
	
	/*
	 * Sets the language file for the error messages.
	 *   
	 * @param  string	$language		The language
	 * @param  string	$languagePath	The path to the language file directory
	 * 
	 * @return	boolean		True for succes, false for failure
	 * 
	 */
	
	function setLanguage($language, $languagePath = JImageLib::DEFAULT_LANGUAGE_DIRECTORY )
	{
		$languagePath = JPATH_SITE . DS . $languagePath;
		
		$params   = JComponentHelper::getParams('com_languages');
		$lg = $params->get('site', 'en-GB');
		$lg = substr($lg, 0, 2);
		
		if ( file_exists($languagePath.'jimagelib.lang-'.$language.'.php')){
			include($languagePath.'jimagelib.lang-'.$language.'.php');
		}
		elseif ( file_exists($languagePath.'jimagelib.lang-'.$lg.'.php')){
			include($languagePath.'jimagelib.lang-en.php');
		}
		elseif ( file_exists($languagePath.'jimagelib.lang-en.php')){
			include($languagePath.'jimagelib.lang-en.php');
		} 
		else {
			$this->setError("Could not load the language file");
			return false;
		}
		
		
		$this->language = $JIMAGELIB_LANG;
		return true;
	}
	
	
	
	
	/*
	 * Returns the error message translated into the specified language
	 * 
	 * @param	string	$code	Error code
	 * 	
	 * @return  string			Message in the specified language or the error code 
	 * 							if the translation failed
	 * 
	 */
	
	function __($code)
	{
		if (! isset($this->language) || count($this->language) < 1) {
			$this->setLanguage("en");
		}
		if (isset($this->language[$code])){
			return $this->language[$code];
		}
		else return $msg;
	}
	
	
	
	
	/*
	 * Gets the parameter from a tag, for a specified property 
	 * 
	 * @param	tag				The tag that will be processed
	 * @param	property		The property to be extracted from the tag
	 * 
	 * @return	string			The parameter for the given property
	 * 
	 */
	
	private function parseProperty(&$tag, $property)
	{
		preg_match( $this->RegEx[$property], $tag, $matches );
		
		if (count($matches) < 1) return '';
		 
		$param = $matches[0];
		$param = preg_replace( '/'.$property.'/i', '', $param, 1);
		$param = str_replace( '=', '', $param );
		$param = str_replace( '\'', '', $param );
		$param = str_replace( '"', '', $param );
        $param = trim($param);
        
        $tag = str_replace($matches[0], '', $tag );
        
        return $param;
	}
	
	
	
	
	/*
	 * Parses the scripting language or <img /> tag given as parameter 
	 * and makes the requested modifications on the object
	 * 
	 * @param	string				The tag to be processed
	 * 
	 * @return	boolean/string		False for a failure, the processed image tag for success
	 * 
	 */
	
	function parse($tag)
	{
		// Adds an extra space at the end of the tag, to avoid problems with the last token
		$tag .= " ";
		 
		// Getting the image filename
	    $fileName = $this->parseProperty(&$tag, 'src');
	    if ($fileName != ''){
	        if (! $this->load($fileName)){
	        	return false;
	        }
	    }
		
		
		
		// Getting the image width
        $width = $this->parseProperty(&$tag, 'width');
        if ($width != ''){
			if (! $this->setWidth((int)$width)){
	        	return false;
	        }
        }    
		
		
		
		// Getting the image height
		$height = $this->parseProperty(&$tag, 'height');
		if ($height != ''){
	        if (! $this->setHeight((int)$height)){
	        	return false;
	        }
		}
		
		// Getting the image library
		$imageLib = $this->parseProperty(&$tag, 'imagelib');
		if ($imageLib != ''){
	        if (! $this->setImageLib($imageLib)){
	        	return false;
	        }
		}
		
		// Getting the alt property
		$alt = $this->parseProperty(&$tag, 'alt');
		if ($alt != ''){
	        if (! $this->setAlt($alt)){
	        	return false;
	        }
		}
		
		// Getting the title property
		$title = $this->parseProperty(&$tag, 'title');
		if ($title != ''){
	        if (! $this->setTitle($title)){
	        	return false;
	        }
		}
		
		// Getting the class property
		$class = $this->parseProperty(&$tag, 'class');
		if ($class != ''){
	        if (! $this->setClass($class)){
	        	return false;
	        }
		}
		
		// Getting the id property
		$id = $this->parseProperty(&$tag, 'id');
		if ($id != ''){
	        if (! $this->setId($id)){
	        	return false;
	        }
		}
		
		
		// Getting filters with parameters
		foreach ($this->filtersWithParams as $filter){
			$param = $this->parseProperty(&$tag, $filter);
			if ($param != ''){
				if ($filter != 'colorize') $param = (int)$param;
		        if (! $this->setFilter($filter, $param)){
		        	return false;
		        }
			}
		}
		
		// Getting filters without parameters
		foreach ($this->filters as $filter){
			if (! in_array($filter, $this->filtersWithParams)){
				$pos = stripos($tag, $filter);
				if ($pos !== false){
					$tag = preg_replace( '/'.$filter.'/i', '', $tag, 1);
					if (! $this->setFilter($filter)){
		        		return false;
		        	}
				}
			}
		}
		
		// Getting the flip direction
		$direction = $this->parseProperty(&$tag, 'flip');
		if ($direction != ''){
	        if (! $this->setFlipping($direction)){
	        	return false;
	        }
		}
		
		
		// Getting the rotation angle
		$angle = $this->parseProperty(&$tag, 'rotate');
		if ($angle != ''){
	        if (! $this->setRotation((int)$angle)){
	        	return false;
	        }
		}
		
				
		// Getting the resize params
		$pos = stripos($tag, 'resize');
		if ($pos !== false){ // resize is requested
			$resize = $this->parseProperty(&$tag, 'resize');
			if ($resize != ''){ // do resizing with params
				if (strtolower($resize) != 'fill'){
			        if (! $this->setResizing($resize)){
			        	return false;
			        }
				}else { // if option is fill, search for fill-color param
					$fill_color = $this->parseProperty(&$tag, 'fill-color');
					if ($fill_color != ''){
	    			    if (! $this->setResizing($resize, $fill_color)){
	        				return false;
	       				 }
					}
					else {
						if (! $this->setResizing($resize)){
	        				return false;
	       				 }
					}
				}
			}
			else {  // resize without parameters
				if (! $this->setResizing()){
		        	return false;
		        }
			}	
		}
		
		
		// Getting the crop margins
		$top = $this->parseProperty(&$tag, 'top');
		$left = $this->parseProperty(&$tag, 'left');
		if ($top != '') $top = (int)$top;
		 	else $top = JImageLib::DEFAULT_TOP_CROP;
		if ($left != '') $left = (int)$left;
		 	else $left = JImageLib::DEFAULT_LEFT_CROP;
		$pos = stripos($tag, 'crop');
		if ($pos !== false){
			$tag = preg_replace( '/crop/i', '', $tag, 1);
			if (! $this->setCropping($top, $left)){
		   		return false;
		   	}
		}
		
		// Getting the options for watermarking
		
		$wm = $this->parseProperty(&$tag, 'wm-file');
		$position = $this->parseProperty(&$tag, 'wm-position');
		$top = $this->parseProperty(&$tag, 'wm-top-margin');
		$left = $this->parseProperty(&$tag, 'wm-left-margin');
		$transparency = $this->parseProperty(&$tag, 'wm-transparency');
		
		$wm_text = $this->parseProperty(&$tag, 'wm-text');
		$wm_font = $this->parseProperty(&$tag, 'wm-font-family');
		$wm_font_size = $this->parseProperty(&$tag, 'wm-font-size');
		$wm_font_color = $this->parseProperty(&$tag, 'wm-font-color');
		
		if ($position == '') $position = JImageLib::DEFAULT_WM_POSITION;
		 
		if ($top != '') $top = (int)$top;
		 	else $top = JImageLib::DEFAULT_WM_MARGIN_TOP;
		 
		if ($left != '') $left = (int)$left;
			else $left = JImageLib::DEFAULT_WM_MARGIN_LEFT;
			
		if ($transparency != '') $transparency = (int)$transparency;
		 	else $transparency = JImageLib::DEFAULT_WM_TRANSPARENCY;
		
		if ($wm_font == '') $wm_font = JImageLib::DEFAULT_WM_FONT_FAMILY;
		
		if ($wm_font_size != '') $wm_font_size = (int)$wm_font_size; 
		 	else $wm_font_size = JImageLib::DEFAULT_WM_FONT_SIZE;

		if ($wm_font_color == '') $wm_font_color = JImageLib::DEFAULT_WM_FONT_COLOR;
		
		$site_path = str_replace('\\', '/', realpath(JPATH_SITE)) . '/';
		$watermark = str_replace('\\', '/', realpath($this->getPath()));
		$watermark = str_replace($site_path, '', $watermark);
		
		if ($wm != ''){
			$this->setName($watermark);
			if (! $newImage = $this->addWatermark($wm, $position, $top, $left, $transparency)){
	        	return false;
	       	}
	       	$this->setName('');
		}
		else if ($wm_text != ''){
			
			$this->setName($watermark);
			if (! $newImage = $this->addWatermarkText($wm_text,$wm_font, $wm_font_size, $wm_font_color, $position, $top, $left, $transparency)){
	        	return false;
	       	}
	       	$this->setName('');
		}
		
		
		/* Getting the pop-up type
		 * (pop-up can be spelled 'pop-up' or 'popup', so it's helpful for user to search both forms
		 */ 
		
		$popUp = $this->parseProperty(&$tag, 'popup');
		if ($popUp != ''){
	        if (! $this->setPopUp($popUp)){
	        	return false;
	        }
		}
		$popUp = $this->parseProperty(&$tag, 'pop-up');
		if ($popUp != ''){
	        if (! $this->setPopUp($popUp)){
	        	return false;
	        }
		}
		
		
		
		// Getting the quality param for saving JPGs
		$quality = $this->parseProperty(&$tag, 'quality');
		if ($quality != ''){
			$quality = (int)quality;
		}
		else $quality = JImageLib::DEFAULT_JPG_QUALITY;
		
		
		
		// Saves the image with the specified quality and removes all the action in order to prevent
		// applying them for the 2nd time, while generating the tag ( getTag  saves the image before generating the tag)

		$this->save('', $quality);
		$this->remove('all');
		
		return $this->getTag();
	}
	
	
	
}
